/**
 * 向父级组件查找指定组件
 * @param {Object} ctx 当前查找起始组件的实例，一般只当前组件this
 * @param {String} componentName 要查找的组件 name
 * @returns
 */
function findComponentUpWard (ctx, componentName) {
  let parent = ctx.$parent
  let name = parent.$options.name
  while (parent && (!name || componentName !== name)) {
    parent = parent.$parent
    if (parent) name = parent.$options.name
  }
  return parent
}

/**
 * 向上查找所有组件实例，返回组件实例数组，多用于递归组件调用
 * @param {Object} ctx 当前查找起始组件的实例，一般只当前组件this
 * @param {String} componentName 要查找的组件 name
 * @returns
 */
function findComponentsUpWard (ctx, componentName) {
  let parents = []
  const parent = ctx.$parent
  if (parent) {
    if (parent.$options.name === componentName) parents.push(parent)
    return parents.concat(findComponentsUpWard(parent, componentName))
  } else {
    return []
  }
}

/**
 * 向下查找指定组件实例，返回组件实例
 * @param {Object} ctx
 * @param {String} componentName
 * @returns
 */
function findComponentDownward (ctx, componentName) {
  const childrens = ctx.$children
  let children = null
  if (childrens.length) {
    for (const vm of childrens) {
      const name = vm.$options.name
      if (name === componentName) {
        children = vm
        break
      } else {
        children = findComponentDownward(vm, componentName)
        if (children) break
      }
    }
  }
  return children
}

/**
 * 向下查找所有组件实例，返回组件实例数组
 * @param {Object} ctx
 * @param {String} componentName
 * @returns
 */
function findComponentsDownward (ctx, componentName) {
  return ctx.$children.reduce((components, child) => {
    if (child.$options.name === componentName) components.push(child)
    const foundChilds = findComponentsDownward(child, componentName)
    return components.concat(foundChilds)
  }, [])
}

/**
 * 查找指定的兄弟组件，返回组件实例数组
 * @param {Object} ctx
 * @param {String} componentName
 * @param {boolean} [exceptMe=true] 是否排除组件自己 默认true
 */
function findComponentsBrothers (ctx, componentName, exceptMe = true) {
  let components = ctx.$parent.$children
  if (components && components.length) {
    let res = components.filter(item => item.$options.name === componentName)
    let myIndex = res.findIndex(item => item._uid === ctx._uid) // 利用vue内置属性_uid判断组件自身位置
    if (exceptMe) res.splice(myIndex, 1)
    return res
  } else {
    return []
  }
}
export {
  findComponentUpWard,
  findComponentsUpWard,
  findComponentDownward,
  findComponentsDownward,
  findComponentsBrothers
}
